#!/usr/bin/env bash
set -e
set -x

PDNS=${PDNS:-../pdns/pdns_server}
PDNS2=${PDNS2:-../pdns/pdns_server}

ALGORITHM=${ALGORITHM:="hmac-md5"}
KEY=${KEY:="kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}

MAKE=${MAKE:-make}

export ALGORITHM
export KEY

trap "kill_process 2" EXIT INT TERM

tosql ()
{
	${MAKE} -C ../pdns zone2sql > /dev/null
	../pdns/zone2sql --transactions --$1 --named-conf=./named.conf
}

bindwait ()
{
	check_process
	configname=$1
	domcount=$(grep -c ^zone named.conf)
	if [ ! -x ../pdns/pdns_control ]
	then
		echo "No pdns_control found"
		exit
	fi
	loopcount=0

	while [ $loopcount -lt 20 ]
	do
		sleep 5
		done=$( (../pdns/pdns_control --config-name=$configname --socket-dir=. --no-config bind-domain-status || true) | grep -c 'parsed into memory' || true )
		if [ $done = $domcount ]
		then
			return
		fi
		let loopcount=loopcount+1
	done

	if [ $done != $domcount ]
	then
		echo "Domain parsing failed" >> failed_tests
	fi
}

securezone ()
{
	local zone=$1
	local configname=$2

	if [ -n "$configname" ]
	then
		configname="--config-name=$configname"
	fi
	if [ "${zone: 0:16}" = "secure-delegated" ]
	then
		../pdns/pdnssec --config-dir=. $configname import-zone-key $zone $zone.private ksk 2>&1
		../pdns/pdnssec --config-dir=. $configname add-zone-key $zone 1024 zsk 2>&1
		keyid=`../pdns/pdnssec --config-dir=. $configname show-zone $zone | grep ZSK | cut -d' ' -f3`
		../pdns/pdnssec --config-dir=. $configname activate-zone-key $zone $keyid 2>&1
		../pdns/pdnssec --config-dir=. $configname rectify-zone $zone 2>&1
	else
		# check if PKCS#11 should be used
		if [ "$pkcs11" -eq 1 ]; then
                  if [ "$slot" == "" ]; then
                    slot=0
                  else
                    slot=$((slot+1))
                  fi
                  sudo softhsm --init-token --slot $slot --label label$slot --pin 123$slot --so-pin 123$slot 
                  kid=`../pdns/pdnssec --config-dir=. $configname hsm assign $zone rsasha256 ksk softhsm $slot 123$slot label$slot 2>&1 | grep softhsm | awk '{ print $NF }'` 
# keep this until #1413 is merged
                  kid=`../pdns/pdnssec --config-dir=. $configname show-zone $zone | grep 'ID =.*KSK' | awk '{ print $3 }'`
                  ../pdns/pdnssec --config-dir=. $configname hsm create-key $zone $kid
                  slot=$((slot+1))
                  sudo softhsm --init-token --slot $slot --label label$slot --pin 123$slot --so-pin 123$slot
                  kid=`../pdns/pdnssec --config-dir=. $configname hsm assign $zone rsasha256 zsk softhsm $slot 123$slot label$slot 2>&1 | grep softhsm | awk '{ print $NF }'`
                  kid=`../pdns/pdnssec --config-dir=. $configname show-zone $zone | grep 'ID =.*ZSK' | awk '{ print $3 }'`
                  ../pdns/pdnssec --config-dir=. $configname hsm create-key $zone $kid
                else
                  ../pdns/pdnssec --config-dir=. $configname secure-zone $zone 2>&1
                fi
	fi
}

check_process ()
{
	set +e
	loopcount=0
	while [ $loopcount -lt 5 ]; do
		sleep 1
		pids=$(cat pdns*.pid 2>/dev/null)
		if [ ! -z "$pids" ]
		then
			kill -0 $pids >/dev/null 2>&1
			if [ $? -eq 0 ]
			then
				set -e
				return
			fi
		fi
	let loopcount=loopcount+1
	done
	echo "PowerDNS did not start"
	exit
}

kill_process ()
{
	set +e
	trap - EXIT INT TERM

	if [ $1 -gt 1 ]
	then
		echo "exitvalue$1" >> failed_tests
		./toxml
		./totar
	fi

	pids=$(cat pdns*.pid)

	if [ -n "$pids" ]
	then
		kill $pids
		# make sure they die.
		loopcount=0
		done=0
		while [ $loopcount -lt 10 ] && [ $done -eq 0 ]
		do
			done=1
			for pid in $pids
			do
				kill -0 $pid > /dev/null 2>&1
				if [ $? -eq 0 ];
				then
					done=0
				fi
			done
			let loopcount=loopcount+1
			sleep 1
		done

		kill -9 $pids
	fi

	rm pdns*.pid
	exit $1
}

if [ ! -x $PDNS ]
 then
	echo "$PDNS is not executable binary"
	exit
fi

if [ ! -x $PDNS2 ]
then
	echo "$PDNS2 is not executable binary"
	exit
fi

port=$1
[ -z "$port" ] && port=5300
context=$2
[ -z "$context" ] && context=bind-dnssec
wait=$3
[ -z "$wait" ] && wait=nowait
cachettl=$4
[ -z "$cachettl" ] && cachettl=0
spectest=$5

testsdir=./tests

if [ "$port" = help ] || [ "$context" = help ] || [ "$port" = "--help" ] || [ "$context" = "--help" ]
then
	set +x
	grep -v '^#' << '__EOF__'

Usage: ./start-test-stop <port> [<context>] [wait|nowait] [<cachettl>] [<specifictest>]

context is one of:
bind bind-dnssec bind-dnssec-nsec3 bind-dnssec-nsec3-optout bind-dnssec-nsec3-narrow
geoipbackend geoipbackend-nsec3-narrow
gmysql-nodnssec gmysql gmysql-nsec3 gmysql-nsec3-optout gmysql-nsec3-narrow
goracle-nodnssec goracle goracle-nsec3 goracle-nsec3-optout goracle-nsec3-narrow
gpgsql-nodnssec gpgsql gpgsql-nsec3 gpgsql-nsec3-optout gpgsql-nsec3-narrow
gsqlite3-nodnssec gsqlite3 gsqlite3-nsec3 gsqlite3-nsec3-optout gsqlite3-nsec3-narrow
mydns
opendbx-sqlite3
oracle-nodnssec oracle oracle-nsec3
remotebackend-pipe remotebackend-unix remotebackend-http remotebackend-zeromq
remotebackend-pipe-dnssec remotebackend-unix-dnssec remotebackend-http-dnssec remotebackend-zeromq-dnssec
#remotebackend-pipe-nsec3 remotebackend-unix-nsec3 remotebackend-http-nsec3
#remotebackend-pipe-nsec3-narrow remotebackend-unix-nsec3-narrow remotebackend-http-nsec3-narrow
tinydns
#ext-nsd ext-nsd-nsec ext-nsd-nsec3 ext-bind ext-bind-nsec ext-bind-nsec3

* Add -presigned to any ext-nsd, ext-bind, bind, gmysql or gsqlite3 test (except narrow)
  to test presigned operation.

* Add -both to any bind or gmysql test (except narrow) to
  test normal and presigned operation.

* Add 'wait' (literally) after the context to not kill
  pdns_server immediately after testing. 'nowait' will kill it.

* A cachettl can be supplied if you want to run tests with a
  ttl setting set. The default cachettl is 0.

* Specifictest can be used to run only one single test.
__EOF__
	exit
fi

${MAKE} -C ../pdns sdig saxfr nsec3dig || exit
# Copy original zones because the test might modify them (well only the dyndns stuff, but let's make this work for others as well)
for zone in $(grep 'zone ' named.conf  | cut -f2 -d\")
do
	if [ -f zones/$zone.orig ]
	then
		cp -f zones/$zone.orig zones/$zone
	fi
done

rm -f pdns*.pid
rm -f *_tests

presigned=no
both=no

if [[ "$context" =~ .+-presigned.* ]]
then
	presigned=yes
	port=$((port-100))
	eval "$(echo "$context" | sed -r 's/(.+)(-presigned)(-(.*))?/context=\1 presignedcontext=\4/')"
	if [ -z "$presignedcontext" ]
	then
		presignedcontext=$context
	fi
fi

if [ "${context: -5}" = "-both" ]
then
	both=yes
	port=$((port-100))
	context=${context%-both}
	presignedcontext=$context
fi

optout=0
pkcs11=0

if [ "${context: -13}" = "-nsec3-optout" ]
then
	optout=1
fi

if [ "${context: -7}" = "-pkcs11" ]
then
        pkcs11=1
        context=${context:0:-7}
fi

# check for lua
if grep -q "^#define HAVE_LUA 1" ../config.h
then
  lua_prequery="--lua-prequery-script=./check_stest_source"
  skiplua=0
else
  lua_prequery=""
  skiplua=1
fi

source backends/common

start_master

if [ "$skiplua" == "1" ]; then
	skipreasons="$skipreasons nolua"
fi

check_process

dotests () {
	nameserver=127.0.0.1 ./runtests $spectest
	./toxml
	./totar

	if [ -s "./failed_tests" ]
	then
		for t in `cat failed_tests`
		do
			echo -e "\n\n$t"
			cat ${testsdir}/$t/diff
		done
		if [ "${!1}" -eq 0 ]
		then
			eval "$1=1"
		fi
	fi
}

## TODO: give sdig a timeout

RETVAL=0

export port
export context
export extracontexts
export skipreasons
export testsdir
export optout

sleep 2

if [ $presigned = no ] || [ $both = yes ]
then
	dotests RETVAL
fi

if [ $presigned = yes ] || [ $both = yes ]
then
	start_slave

	export port
	export context
	export skipreasons

	dotests RETVAL
fi

if [ "$wait" = "wait" ]
then
	echo tests done! push enter to terminate instance
	read l
fi

trap "kill_process $RETVAL" EXIT
